#include "opengles2.h"
#include "GLRender.h"

bool mPaused = false;
bool mfInit = false;
int m_nImageW = 320;
int m_nImageH = 240;
unsigned char* m_databuf = 0;
FrameBuffer mCurFrame;

bool mfLandscape = true;
bool mfClipImage = false;
int mGLViewWidth = 800;
int mGLViewHeight = 600;
int mRotation = 0;

GLuint m_textures[3];
int m_aPositionHandle = 0;
int m_aTextureHandle_Y = 0;
int m_aTextureHandle_U = 0;
int m_aTextureHandle_V = 0;
GLuint m_Program = 0;
GLuint m_vertexShader = 0;
GLuint m_fragmentShader = 0;

GLfloat m_brightness = 1.1;
GLfloat m_contrast = 1.2;
GLfloat m_saturation = 1.5;

bool mfCreateprogram = false;
GLfloat mTriangleVerticesData[20];

//图锟斤拷锟斤拷锟揭碉拷锟矫匡拷锟斤拷
#define SWITCH_IMAGE_LEFTTORIGHT 1

//锟斤拷锟矫碉拷锟斤拷锟姐法
#define PREWITT 0
#define SOBEL   0
#define LAPLACIAN 0
//锟斤拷锟矫碉拷平锟斤拷去锟斤拷锟姐法
#define AVG3X3_SMOOTH 0
#define AVG3X3_SMOOTH_EXT 0
//锟斤拷锟斤拷锟斤拷锟饺★拷锟皆比度★拷锟斤拷锟酵讹拷
#define ADJUST_BRIGHTNESS 1
#define ADJUST_CONTRAST   1
#define ADJUST_SATURATION 1
//锟斤拷锟斤拷锟斤拷系锟斤拷锟斤拷锟斤拷锟�
#define SHARPENCOEFF 0

const static int FLOAT_SIZE_BYTES = 4;
const static int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 20;

GLfloat texCoordOffsets[18];

static const char gVertexShader[] =
"attribute vec4 aPosition;\n"

"attribute vec2 aTextureCoord_Y;\n"
"varying vec2 vTextureCoord_Y;\n"

"attribute vec2 aTextureCoord_U;\n"
"varying vec2 vTextureCoord_U;\n"

"attribute vec2 aTextureCoord_V;\n"
"varying vec2 vTextureCoord_V;\n"

"void main() {\n"
"  gl_Position = aPosition;\n"

"  vTextureCoord_Y = aTextureCoord_Y;\n"
"  vTextureCoord_U = aTextureCoord_U;\n"
"  vTextureCoord_V = aTextureCoord_V;\n"

"}\n";


static const char gFragmentShader[] =
"precision mediump float;\n"

"varying vec2 vTextureCoord_Y;\n"
"varying vec2 vTextureCoord_U;\n"
"varying vec2 vTextureCoord_V;\n"
"uniform sampler2D sTexture_Y;\n"
"uniform sampler2D sTexture_U;\n"
"uniform sampler2D sTexture_V;\n"

"const vec3 delyuv = vec3(-16.0/255.0,-128.0/255.0,-128.0/255.0);\n"
"const vec3 matYUVRGB1 = vec3(1.0,0.0,1.14);\n"
"const vec3 matYUVRGB2 = vec3(1.0,-0.390,-0.58);\n"
"const vec3 matYUVRGB3 = vec3(1.0,2.03,0.0);\n"

"uniform float brightness;\n"
"uniform vec3 AvgLuminance;\n"
"uniform float contrast;\n"
"const vec3 lumcoeff = vec3(0.2125,0.7154,0.0721);\n"
"uniform float saturation;\n"
"uniform vec2 tc_offset[9];\n"
"uniform float sharpAlpha;\n"

"void main() {\n"

"vec3 sample[9];\n"
"vec3 yuvData;\n"
"vec3 CurResult;\n"
"float delta;\n"

"yuvData.x = (texture2D(sTexture_Y, vTextureCoord_Y).x);\n"
"yuvData.y = (texture2D(sTexture_U, vTextureCoord_U).x);\n"
"yuvData.z = (texture2D(sTexture_V, vTextureCoord_V).x);\n"

"for (int i = 0; i < 9; i++)\n"
"{\n"
"	sample[i].x = (texture2D(sTexture_Y, vTextureCoord_Y + tc_offset[i])).x;\n"
"	sample[i].y = (texture2D(sTexture_U, vTextureCoord_U + tc_offset[i])).y;\n"
"	sample[i].z = (texture2D(sTexture_V, vTextureCoord_V + tc_offset[i])).z;\n"
"}\n"

"yuvData += delyuv;\n"

//锟今化达拷锟斤拷

#if LAPLACIAN
//锟今化达拷锟斤拷laplacian微锟斤拷锟斤拷锟接憋拷锟斤拷
//   -1 -1 -1
//   -1  9 -1
//   -1 -1 -1

      //"CurResult = (sample[4] * 9.0) - \n"
      //"(sample[0] + sample[1] + sample[2] + \n"
      //" sample[3] + sample[5] + \n"
      //" sample[6] + sample[7] + sample[8]);\n"

	  /*"delta = ((sample[4].x) * 12.0) - \n"
	  "((sample[0].x) + (sample[1].x) * 2.0 + \n"
	  " (sample[2].x) + (sample[3].x) * 2.0 + \n"
	  " (sample[6].x) + (sample[5].x) * 2.0 + \n"
	  " (sample[8].x) + (sample[7].x) * 2.0); \n"

	  "yuvData.x += delta/12.0;\n"*/


	  "delta = ((sample[4].x) * 4.0) - \n"
	  "((sample[1].x) + (sample[3].x)  + \n"
	  " (sample[5].x) + (sample[7].x) )  ; \n"


	  "yuvData.x += delta/8.0;\n"

#endif

#if PREWITT
//    -1 -1 -1       1 0 -1
// H = 0  0  0   V = 1 0 -1
//     1  1  1       1 0 -1
//
// result = sqrt(H^2 + V^2)

       "float horizEdge = sample[2].x + sample[5].x + sample[8].x - \n"
       "(sample[0].x + sample[3].x + sample[6].x);\n"

       "float vertEdge = sample[0].x + sample[1].x + sample[2].x - \n"
       "(sample[6].x + sample[7].x + sample[8].x);\n"

        "yuvData.x = sqrt((horizEdge * horizEdge) + \n"
         "					(vertEdge * vertEdge)); \n"

#endif

#if SOBEL
//    -1 -2 -1       1 0 -1
// H = 0  0  0   V = 2 0 -2
//     1  2  1       1 0 -1
//
// result = sqrt(H^2 + V^2)

        "vec4 horizEdge = sample[2] + (2.0*sample[5]) + sample[8] - \n"
        "(sample[0] + (2.0*sample[3]) + sample[6]);\n"

        "vec4 vertEdge = sample[0] + (2.0*sample[1]) + sample[2] - \n"
        "(sample[6] + (2.0*sample[7]) + sample[8]);\n"

        "yuvData.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + \n"
        "                 (vertEdge.rgb * vertEdge.rgb));\n"

#endif


//锟斤拷系锟斤拷锟斤拷锟斤拷锟�
#if SHARPENCOEFF

"     vec3 colorsharp = yuvData.rgb * sharpAlpha + yuvData.rgb * (1.0 - sharpAlpha);\n"
      "yuvData.rgb = colorsharp;\n"

#endif

//图锟斤拷锟诫，平锟斤拷锟斤拷锟斤拷
#if AVG3X3_SMOOTH
       "yuvData = (sample[4] + \n"
       "sample[0] + sample[1] + sample[2] + \n"
       " sample[3] + sample[5] + \n"
       " sample[6] + sample[7] + sample[8])/9.0;\n"
#endif

#if AVG3X3_SMOOTH_EXT
       "yuvData = (sample[0] + (2.0*sample[1]) + sample[2] + \n"
       "			(2.0*sample[3]) + sample[4] + (2.0*sample[5]) + \n"
       "			sample[6] + (2.0*sample[7]) + sample[8]) / 13.0;\n"
#endif

//锟斤拷锟饺碉拷锟斤拷
#if ADJUST_BRIGHTNESS

      "yuvData.x = yuvData.x * brightness;\n"

#endif

	  /*"if (yuvData.x > 1.0)\n"
	  "{\n"
	  "    yuvData.x == 1.0;\n"
	  "}\n"
	  "if (yuvData.x < 0.0)\n"
	  "{\n"
	  "    yuvData.x == 0.0;\n"
	  "}\n"*/
       "CurResult.x = dot(yuvData,matYUVRGB1);\n"
	   "CurResult.y = dot(yuvData,matYUVRGB2);\n"
	   "CurResult.z = dot(yuvData,matYUVRGB3);\n"

//锟皆比讹拷
#if ADJUST_CONTRAST

      "yuvData.rgb = mix(AvgLuminance,yuvData.rgb,contrast);\n"

#endif

//锟斤拷锟酵讹拷
#if ADJUST_SATURATION

       "vec3 intensity = vec3(dot(CurResult.rgb,lumcoeff));\n"
       "CurResult.rgb = mix(intensity,CurResult.rgb,saturation);\n"

#endif

	   "gl_FragColor.rgb = CurResult.rgb;\n"
       "gl_FragColor.w = 1.0;\n"

"}\n";

bool setupGraphics(int w, int h) {
	printGLString("Version", GL_VERSION);
	printGLString("Vendor", GL_VENDOR);
	printGLString("Renderer", GL_RENDERER);
	printGLString("Extensions", GL_EXTENSIONS);

	LOGI("setupGraphics(%d, %d)", w, h);
	m_Program = createProgram(gVertexShader, gFragmentShader, &m_vertexShader, &m_fragmentShader);
	if (!m_Program) {
		LOGE("Could not create program.");
		return false;
	}

	m_aPositionHandle = glGetAttribLocation(m_Program, "aPosition");
	checkGlError("glGetAttribLocation aPosition");

	m_aTextureHandle_Y = glGetAttribLocation(m_Program, "aTextureCoord_Y");
	checkGlError("glGetAttribLocation aTextureCoord_Y");
	m_aTextureHandle_U = glGetAttribLocation(m_Program, "aTextureCoord_U");
	checkGlError("glGetAttribLocation aTextureCoord_U");
	m_aTextureHandle_V = glGetAttribLocation(m_Program, "aTextureCoord_V");
	checkGlError("glGetAttribLocation aTextureCoord_V");

	return true;
}

void prepareTex()
{
	glGenTextures(1,&m_textures[0]);
	glGenTextures(1,&m_textures[1]);
	glGenTextures(1,&m_textures[2]);
}

void ChangeSize(int w, int h)
{
	GLint i, j;
	GLfloat xInc, yInc;

	xInc = 1.0f / (GLfloat)w;
	yInc = 1.0f / (GLfloat)h;

	LOGI("ChangeSize xInc = %f, yInc = %f",xInc,yInc);

	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			texCoordOffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
			texCoordOffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);

			LOGI("ChangeSize texCoordOffsets[%d][%d].x = %f, texCoordOffsets[%d][%d].y = %f",
				i,j,texCoordOffsets[(((i*3)+j)*2)+0],i,j,texCoordOffsets[(((i*3)+j)*2)+1]);
		}
	}
}

void init_impl()
{

	if(mfCreateprogram == false){
		prepareTex();
		setupGraphics(m_nImageW, m_nImageH);
		mfCreateprogram = true;
	}

	if(mfInit){
		ChangeSize(m_nImageW,m_nImageH);
		mfInit = false;
	}
}

void setFrame(FrameBuffer *fp)
{
	if(fp->mpData){
		if(mPaused){
			clearCurFrame();
		}else{
			mCurFrame = *fp;
		}
	}
}

bool _getvideoframe()
{
	if(mGLViewWidth == 0 || mGLViewHeight == 0){
		return false;
	}

	if(mCurFrame.mpData){
		m_databuf = (unsigned char*)(mCurFrame.mpData);
	}
	return mCurFrame.mpData?true: false;
}

void clearCurFrame()
{
	if(mCurFrame.mpData){
		m_databuf = (unsigned char*)(mCurFrame.mpData);
		if(m_databuf){
			memset(m_databuf,0,size(&mCurFrame));
			int uv = size(&mCurFrame) *2 /3;
			memset(m_databuf + uv,128,uv/2);
		}
	}
}

void flush(bool all)
{
	if(all){
		clearCurFrame();
	}
}

void pause()
{
	mPaused = true;
}

void resume()
{
	mPaused = false;
}

void UnInit()
{
	LOGD("UnInit()");
	flush(false);
	clearCurFrame();
	mfCreateprogram = false;
	//deleteProgram(m_Program, m_vertexShader, m_fragmentShader);
	m_Program = 0;
	//m_vertexShader = 0;
	//m_fragmentShader = 0;
}

void Init(int w, int h)
{
	if(mfCreateprogram == false)
	{
		mfInit = true;
		m_nImageW = w;
		m_nImageH = h;
	}
	else
	{
		if((w != m_nImageW) || (h != m_nImageH))
		{
			mfInit = true;
			m_nImageW = w;
			m_nImageH = h;
		}
	}
}

void _checkDisplayAngle(){
	int angle = (getDisplayAngle(&mCurFrame) + mRotation) % 4;
	bool fMirror = isMirror(&mCurFrame);
	if(mfClipImage){
		int sW = m_nImageW;
		int sH =  m_nImageH;

		float fsrc = sW;
		fsrc /= sH;
		if(angle == 1 || angle == 3){
			fsrc = 1.0f /fsrc;
			sW = m_nImageH;
			sH = m_nImageW;
		}

		float fdst = mGLViewWidth;
		fdst /= mGLViewHeight;

		float fxscale = 0.0f;
		float fyscale = 0.0f;

		if(fsrc > fdst){
			//clip width
			fxscale = mGLViewWidth*sH;
			fxscale /= (mGLViewHeight*sW);
			fxscale = (1.0f - fxscale)/2;
		}else{
			//clip height
			fyscale = mGLViewHeight* sW;
			fyscale /= (mGLViewWidth * sH);
			fyscale = (1.0f - fyscale)/2;
		}

		if(angle == 1 || angle == 3){
			float temp = fyscale;
			fyscale = fxscale;
			fxscale = temp;
		}
		switch(angle){
		case 3: //270  degree
		mTriangleVerticesData[0] = -1.0f;
		mTriangleVerticesData[1] = -1.0f;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = fxscale;
		mTriangleVerticesData[4] = fMirror ? 1.0f-fyscale : fyscale;
		mTriangleVerticesData[5] = -1.0f;
		mTriangleVerticesData[6] = 1.0f;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = 1.0f-fxscale;
		mTriangleVerticesData[9] = fMirror ? 1.0 - fyscale : fyscale;
		mTriangleVerticesData[10] = 1.0f;
		mTriangleVerticesData[11] = -1.0f;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = fxscale;
		mTriangleVerticesData[14] = fMirror ? fyscale : 1.0f-fyscale;
		mTriangleVerticesData[15] = 1.0f;
		mTriangleVerticesData[16] = 1.0f;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = 1.0f-fxscale;
		mTriangleVerticesData[19] = fMirror ? fyscale : 1.0f-fyscale;
		break;
		case 2: //180 degree
	 	mTriangleVerticesData[0] = 1.0f;
		mTriangleVerticesData[1] = -1.0f;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = fMirror ? 1.0f-fxscale : fxscale;
		mTriangleVerticesData[4] = fyscale;
		mTriangleVerticesData[5] = -1.0f;
		mTriangleVerticesData[6] = -1.0f;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = fMirror ? fxscale : 1.0f-fxscale;
		mTriangleVerticesData[9] = fyscale;
		mTriangleVerticesData[10] = 1.0f;
		mTriangleVerticesData[11] = 1.0f;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = fMirror ? 1.0f-fxscale : fxscale;
		mTriangleVerticesData[14] = 1.0f-fyscale;
		mTriangleVerticesData[15] = -1.0f;
		mTriangleVerticesData[16] = 1.0f;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = fMirror ? fxscale : 1.0f-fxscale;
		mTriangleVerticesData[19] = 1.0f-fyscale;
		break;
		case 1: //90 degree
		mTriangleVerticesData[0] = 1.0f;
		mTriangleVerticesData[1] = 1.0f;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = fxscale;
		mTriangleVerticesData[4] = fMirror ? 1.0f-fyscale : fyscale;
		mTriangleVerticesData[5] = 1.0f;
		mTriangleVerticesData[6] = -1.0f;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = 1.0f-fxscale;
		mTriangleVerticesData[9] = fMirror ? 1.0f-fyscale : fyscale;
		mTriangleVerticesData[10] = -1.0f;
		mTriangleVerticesData[11] = 1.0f;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = fxscale;
		mTriangleVerticesData[14] = fMirror ? fyscale : 1.0f-fyscale;
		mTriangleVerticesData[15] = -1.0f;
		mTriangleVerticesData[16] = -1.0f;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = 1.0f-fxscale;
		mTriangleVerticesData[19] = fMirror ? fyscale : 1.0f-fyscale;
		break;
		default://0 degree
		mTriangleVerticesData[0] = -1.0f;
		mTriangleVerticesData[1] = 1.0f;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = fMirror ? 1.0f-fxscale : fxscale;
		mTriangleVerticesData[4] = fyscale;
		mTriangleVerticesData[5] = 1.0f;
		mTriangleVerticesData[6] = 1.0f;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = fMirror ? fxscale : 1.0f-fxscale;
		mTriangleVerticesData[9] = fyscale;
		mTriangleVerticesData[10] = -1.0f;
		mTriangleVerticesData[11] = -1.0f;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = fMirror ? 1.0f-fxscale : fxscale;
		mTriangleVerticesData[14] = 1.0f-fyscale;
		mTriangleVerticesData[15] = 1.0f;
		mTriangleVerticesData[16] = -1.0f;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = fMirror ? fxscale : 1.0f-fxscale;
		mTriangleVerticesData[19] = 1.0f-fyscale;
		break;
		}
	}else{
		float xfscale = 1.0f;
		float yfscale = 1.0f;

		if(angle == 0 || angle == 2){
			if(!mfLandscape){
				xfscale = 1.0f;
				yfscale = (m_nImageH*mGLViewWidth)/(float)(m_nImageW*mGLViewHeight) ;
			}else{
				yfscale = 1.0f;
				xfscale = (m_nImageW*mGLViewHeight)/(float)(m_nImageH*mGLViewWidth) ;
			}
		}else{
			if(!mfLandscape){
				yfscale = 1.0f - (m_nImageW*mGLViewWidth)/(float)(m_nImageH*mGLViewHeight) ;
				xfscale = 1.0f;
			}else{
				yfscale = 1.0f;
				xfscale = 1.0f -(m_nImageH*mGLViewHeight)/(float) (m_nImageW*mGLViewWidth);
			}
		}

		switch(angle){
		case 3: //270  degree
		mTriangleVerticesData[0] = 0.0f -xfscale;
		mTriangleVerticesData[1] = -1.0f + yfscale;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = 0.0f;// fMirror ? 1.0f : 0.0f;
		mTriangleVerticesData[4] = fMirror ? 1.0f : 0.0f;

		mTriangleVerticesData[5] = 0.0f -xfscale;
		mTriangleVerticesData[6] = 1.0f -yfscale;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = 1.0f;//fMirror ? 0.0f : 1.0f;
		mTriangleVerticesData[9] = fMirror ? 1.0f : 0.0f;

		mTriangleVerticesData[10] = xfscale;
		mTriangleVerticesData[11] = -1.0f +yfscale;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = 0.0f;//fMirror ? 1.0f : 0.0f;
		mTriangleVerticesData[14] = fMirror ? 0.0f :1.0f;

		mTriangleVerticesData[15] = xfscale;
		mTriangleVerticesData[16] = 1.0f -yfscale;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = 1.0f;//fMirror ? 0.0f : 1.0f;
		mTriangleVerticesData[19] = fMirror ? 0.0f :1.0f;
		break;
		case 2: //180 degree
	 	mTriangleVerticesData[0] = -1.0f;
		mTriangleVerticesData[1] = yfscale;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = fMirror ? 0.0f : 1.0f;
		mTriangleVerticesData[4] = 1.0f;

		mTriangleVerticesData[5] = 1.0f;
		mTriangleVerticesData[6] = yfscale;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = fMirror ? 1.0f : 0.0f;
		mTriangleVerticesData[9] = 1.0f;

		mTriangleVerticesData[10] = -1.0f;
		mTriangleVerticesData[11] = 0.0f - yfscale;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = fMirror ? 0.0f : 1.0f;
		mTriangleVerticesData[14] = 0.0f;

		mTriangleVerticesData[15] = 1.0f;
		mTriangleVerticesData[16] = 0.0f - yfscale;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = fMirror ? 1.0f : 0.0f;
		mTriangleVerticesData[19] = 0.0f;
		break;
		case 1: //90 degree
		mTriangleVerticesData[0] = xfscale;
		mTriangleVerticesData[1] = 1.0f-yfscale;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = 0.0f;
		mTriangleVerticesData[4] = fMirror ? 0.0f : 1.0f;

		mTriangleVerticesData[5] = xfscale;
		mTriangleVerticesData[6] = -1.0f +yfscale;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = 1.0f;
		mTriangleVerticesData[9] = fMirror ? 0.0f : 1.0f;

		mTriangleVerticesData[10] = 0.0f -xfscale;
		mTriangleVerticesData[11] = 1.0f -yfscale;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = 0.0f;
		mTriangleVerticesData[14] = fMirror ? 1.0f : 0.0f;

		mTriangleVerticesData[15] = 0.0f -xfscale;
		mTriangleVerticesData[16] = -1.0f +yfscale;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = 1.0f;
		mTriangleVerticesData[19] = fMirror ? 1.0f : 0.0f;
		break;
		default://0 degree
		mTriangleVerticesData[0] = -1.0f;
		mTriangleVerticesData[1] = yfscale;
		mTriangleVerticesData[2] = 0; //
		mTriangleVerticesData[3] = fMirror ? 1.0f : 0.0f;
		mTriangleVerticesData[4] = 0.0f;

		mTriangleVerticesData[5] = 1.0f;
		mTriangleVerticesData[6] = yfscale;
		mTriangleVerticesData[7] = 0;//
		mTriangleVerticesData[8] = fMirror ? 0.0f : 1.0f;
		mTriangleVerticesData[9] = 0.0f;

		mTriangleVerticesData[10] = -1.0f;
		mTriangleVerticesData[11] = 0.0f -yfscale;
		mTriangleVerticesData[12] = 0; //
		mTriangleVerticesData[13] = fMirror ? 1.0f : 0.0f;
		mTriangleVerticesData[14] = 1.0f;

		mTriangleVerticesData[15] = 1.0f;
		mTriangleVerticesData[16] = 0.0f -yfscale;
		mTriangleVerticesData[17] = 0; //
		mTriangleVerticesData[18] = fMirror ? 0.0f : 1.0f;
		mTriangleVerticesData[19] = 1.0f;
		break;
		}
	}
}

void renderView()
{
	if(_getvideoframe() == false){
		LOGE("no video frame for render!");
		return;
	}
	init_impl();

	int datatype = getBufferType(&mCurFrame);
	if(datatype != def_DataType_YUV420P){
		LOGW("opengl2 render err! need I420");
		return;
	}

	int i,j;

	int iloop,jloop;
	GLfloat fr,fg,fb;
	int loopCnt;
	unsigned long starttime = 0;
	unsigned long endtime = 0;

	int histogram[256];
	for(i = 0; i < 256; i++)
		histogram[i] = 0;

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, m_textures[0]);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,m_nImageW,m_nImageH,0,GL_LUMINANCE,
		GL_UNSIGNED_BYTE,m_databuf);

	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, m_textures[1]);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,m_nImageW/2,m_nImageH/2,0,GL_LUMINANCE,
		GL_UNSIGNED_BYTE,m_databuf+m_nImageW*m_nImageH);

	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, m_textures[2]);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE,m_nImageW/2,m_nImageH/2,0,GL_LUMINANCE,
		GL_UNSIGNED_BYTE,m_databuf+m_nImageW*m_nImageH+m_nImageW*m_nImageH/4);

	glUseProgram(m_Program);
	checkGlError("glUseProgram");

	 _checkDisplayAngle();

	glVertexAttribPointer(m_aPositionHandle, 3, GL_FLOAT, false,
		TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVerticesData);
	checkGlError("glVertexAttribPointer maPosition");
	glEnableVertexAttribArray(m_aPositionHandle);
	checkGlError("glEnableVertexAttribArray maPositionHandle");

	glVertexAttribPointer(m_aTextureHandle_Y, 2, GL_FLOAT, false,
		TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVerticesData+3);
	checkGlError("glVertexAttribPointer maTextureHandle");
	glEnableVertexAttribArray(m_aTextureHandle_Y);
	checkGlError("glEnableVertexAttribArray maTextureHandle");

	glVertexAttribPointer(m_aTextureHandle_U, 2, GL_FLOAT, false,
		TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVerticesData+3);
	checkGlError("glVertexAttribPointer maTextureHandle");
	glEnableVertexAttribArray(m_aTextureHandle_U);
	checkGlError("glEnableVertexAttribArray m_aTextureHandle_U");

	glVertexAttribPointer(m_aTextureHandle_V, 2, GL_FLOAT, false,
		TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVerticesData+3);
	checkGlError("glVertexAttribPointer maTextureHandle");
	glEnableVertexAttribArray(m_aTextureHandle_V);
	checkGlError("glEnableVertexAttribArray m_aTextureHandle_V");



	GLuint textureY = glGetUniformLocation(m_Program,"sTexture_Y");
	checkGlError("glGetUniformLocation sTexture_Y");
	glUniform1i(textureY,0);
	checkGlError("glUniform1i sTexture_Y");

	GLuint textureU = glGetUniformLocation(m_Program,"sTexture_U");
	checkGlError("glGetUniformLocation sTexture_U");
	glUniform1i(textureU,1);
	checkGlError("glUniform1i sTexture_U");

	GLuint textureV = glGetUniformLocation(m_Program,"sTexture_V");
	checkGlError("glGetUniformLocation sTexture_V");
	glUniform1i(textureV,2);
	checkGlError("glUniform1i sTexture_V");


	glClearColor(0,0,0,0);
	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

#if 0
	unsigned long clip_thld = (unsigned long)(m_nImageW * m_nImageH * 0.02);
	unsigned long do_level_thld = 128;
	long hist_y[256] = {0};
	unsigned char* tmpdata = m_databuf;
	unsigned long y_max = 0;
	unsigned long y_newmax = 0;
	unsigned long fraction = 0;

	for (i=0; i<m_nImageW*m_nImageH; i++)
	{
		++hist_y[*tmpdata];
		++tmpdata;
	}


	for (i=255; i>0; --i)
	{
		if (hist_y[i] != 0)
		{
			y_max = i;
			break;
		}
	}

	for (i=y_max; i>0; i--)
	{
		fraction += hist_y[i];
		if (fraction >= clip_thld)
		{
			y_newmax = i;
			break;
		}
	}


	float co;

	if (y_newmax == 0)
	{
		co = 1.0;
	}
	else
	{
		co = 255.0/(float)y_newmax;
	}


    if (co > 1.2)
    {
        co = 1.2;
    }
#endif


	GLint brightness = glGetUniformLocation(m_Program,"brightness");
	checkGlError("glGetUniformLocation brightness");
	//glUniform1f(brightness,co);
	glUniform1f(brightness,m_brightness);
	checkGlError("glUniform1f brightness");


	GLint contrast = glGetUniformLocation(m_Program,"contrast");
	checkGlError("glGetUniformLocation contrast");
	glUniform1f(contrast,m_contrast);
	checkGlError("glUniform1f contrast");


	GLint saturation = glGetUniformLocation(m_Program,"saturation");
	checkGlError("glGetUniformLocation saturation");
	glUniform1f(saturation,m_saturation);
	checkGlError("glUniform1f saturation");


	GLint sharpAlpha = glGetUniformLocation(m_Program,"sharpAlpha");
	checkGlError("glGetUniformLocation sharpAlpha");
	glUniform1f(sharpAlpha,0);
	checkGlError("glUniform1f sharpAlpha");


	GLint tc_offset = glGetUniformLocation(m_Program, "tc_offset");
	checkGlError("glGetUniformLocation tc_offset");
	glUniform2fv(tc_offset, 9, texCoordOffsets);

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	checkGlError("glDrawArrays");

}

void setColorAdjust(float brightness, float contrast, float saturation)
{
	m_brightness = brightness;
	m_contrast = contrast;
	m_saturation = saturation;
}

void setDisplayMode(int view_width, int view_height, bool fScreenLandscape, bool clip4match)
{
	mGLViewWidth = view_width;
	mGLViewHeight = view_height;

	mfLandscape = fScreenLandscape;
	mfClipImage = clip4match;
}

void setRotation(int rotation)
{
	rotation = rotation % 360;
	switch(rotation){
	case 270: //270  degree
		mRotation = 3;
		break;
	case 180: //180 degree
		mRotation = 2;
		break;
	case 90: //90 degree
		mRotation = 1;
		break;
	default://0 degree
		mRotation = 0;
		break;
	}
}

int getRotation()
{
	return mRotation * 90;
}

#include "com_vc_opengl_GLRender.h"

/* This is a trivial JNI example where we use a native method
 * to return a new VM String. See the corresponding Java source
 * file located at:
 *
 *   apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java
 */
void
Java_com_vc_opengl_GLRender_init
  (JNIEnv *env, jobject clazz, jint glVersion, jobject glRender)
{
	LOGI("init\n");

	(*env)->GetJavaVM(env, &g_jvm);

	jclass render_cls = (*env)->GetObjectClass(env, clazz);
	if (render_cls == 0)
	{
		LOGE("render_cls is null\n");
		return;
	}
	
  	g_render_cls = (jclass)(*env)->NewGlobalRef(env, render_cls);
  	if (g_render_cls == 0)
	{
		LOGE("g_render_cls is null\n");
		return;
	}
	
	g_render_obj = (*env)->NewGlobalRef(env, glRender);
	if (g_render_obj == 0)
	{
		LOGE("g_render_obj is null\n");
		return;
	}
	
	g_render_mid = (*env)->GetStaticMethodID(env, g_render_cls, "onNativeNotify","(Ljava/lang/Object;ILjava/lang/Object;)V");
	if (g_render_mid == 0)
	{
		LOGE("g_render_mid is null\n");
		return;
	}
	
	Init(320, 240);
    return;
}

void
Java_com_vc_opengl_GLRender_render
  (JNIEnv *env, jobject clazz)
{
	renderView();
    return;
}

void
Java_com_vc_opengl_GLRender_onPause
  (JNIEnv * env, jobject clazz)
{
	LOGI("onPause");
	pause();
    return;
}

void
Java_com_vc_opengl_GLRender_onResume
  (JNIEnv * env, jobject clazz)
{
	LOGI("onResume");
	resume();
    return;
}

void 
Java_com_vc_opengl_GLRender_setParam
  (JNIEnv *env, jobject clazz, jfloat mBrightness, jfloat mContrast, jfloat mSaturation)
{
	LOGI("setParam");
	setColorAdjust(mBrightness, mContrast, mSaturation);
    return;
}

void 
Java_com_vc_opengl_GLRender_Uninit
  (JNIEnv *env, jobject clazz)
{
	if (g_vedio_buffer)
	{
		free(g_vedio_buffer);
		g_vedio_buffer = NULL;
	}
	g_vedio_buffer_size = 0;
	
	if (g_audio_buffer)
	{
		free(g_audio_buffer);
		g_audio_buffer = NULL;
	}
	g_audio_buffer_size = 0;
	
	UnInit();

    return;
}

void 
Java_com_vc_opengl_GLRender_flush
  (JNIEnv *env, jobject clazz, jboolean paramBoolean)
{
	LOGI("flush:%d", paramBoolean?1:0);
	flush(paramBoolean);
    return;
}

void 
Java_com_vc_opengl_GLRender_setRotation
  (JNIEnv *env, jobject clazz, jint rotation)
{
	LOGI("setRotation:%d", rotation);
	setRotation(rotation);
    return;
}

jint 
Java_com_vc_opengl_GLRender_getRotation
  (JNIEnv *env, jobject clazz)
{
	LOGI("setRotation");
    return getRotation();
}

void 
Java_com_vc_opengl_GLRender_setDisplayMode
  (JNIEnv *env, jobject clazz, jint width, jint height, jboolean mfLandscape, jboolean mfClip)
{
	LOGI("setDisplayMode:%d,%d,%d,%d", width, height, mfLandscape?1:0, mfClip?1:0);
	setDisplayMode(width, height, mfLandscape, mfClip);
    return;
}
